﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace DotNetCommon.Extensions
{
    /// <summary>
    /// 提供IfNullUse系列扩展方法
    /// </summary>
    public static class IfNullUseExtensions
    {
        #region 引用类型的IfNullUse
        /// <summary>
        /// 如果为null, 则返回 value, 如:
        /// <code>
        /// public class User { public int Id {get;set;} }
        /// User user = null;
        /// var id = user.IfNullUse(new User{ Id = 1}).Id; //相当于 var id = (user??new User{ Id = 1}).Id;
        /// </code>
        /// </summary>
        public static T IfNullUse<T>(this T obj, T value) where T : class => obj ?? value;

        private static Func<ConstructorInfo, ParameterInfo[]> _getParameters = null;
        private static object _getParameters_lock = new();
        private static ConcurrentDictionary<Type, Func<object>> _newCaches = new();

        /// <summary>
        /// 如果为null, 则返回 new(), 如:
        /// <code>
        /// public class User { public int Id {get;set;} }
        /// User user = null; 
        /// var id = user.IfNullUseNew().Id; //相当于 var id = (user??new User()).Id;
        /// </code>
        /// </summary>
        public static T IfNullUseNew<T>(this T obj) where T : class
        {
            if (obj != null) return obj;
            var type = typeof(T);
            if (type.IsAbstract)
            {
                if (type.IsSealed) throw new Exception($"不能对静态类: {type.GetClassFullName()} 使用 new()!");
                else if (type.IsSealed) throw new Exception($"不能对抽象类: {type.GetClassFullName()} 使用 new()!");
            }
            if (type.IsInterface) throw new Exception($"不能对接口: {type.GetClassFullName()} 使用 new()!");
            //不需要考虑这种: int?, 因为 int? i=null; i.IfNullUseNew() 编译会报错
            var func = _newCaches.GetOrAdd(type, type =>
              {
                  initGetParameters();
                  var ctors = type.GetConstructors();
                  var pairs = new List<(ConstructorInfo ctor, ParameterInfo[] paras, int hasNoDefaultValueCount)>(ctors.Length);
                  for (var i = 0; i < ctors.Length; i++)
                  {
                      var ctor = ctors[i];
                      var paras = _getParameters(ctor);
                      if (paras.Length == 0)
                      {
                          //如果有空参构造函数,直接使用即可
                          return Expression.Lambda<Func<object>>(Expression.New(ctor)).Compile();
                      }
                      //加入备选
                      pairs.Add((ctor, paras, paras.Count(i => !i.HasDefaultValue)));
                  }
                  //没有默认值的参数越少越好, 参数的数量越少越好
                  var best = pairs.OrderBy(i => i.paras.Length).OrderBy(i => i.hasNoDefaultValueCount).First();
                  var expParas = best.paras.Select(i =>
                  {
                      //有默认值设置就使用默认值,否则使用 default
                      if (i.HasDefaultValue) return Expression.Convert(Expression.Constant(i.DefaultValue), i.ParameterType);
                      return Expression.Default(i.ParameterType) as Expression;
                  }).ToArray();
                  return Expression.Lambda<Func<object>>(Expression.New(best.ctor, expParas)).Compile();
              });
            return (T)func();
        }
        private static void initGetParameters()
        {
            if (_getParameters == null)
            {
                lock (_getParameters_lock)
                {
                    if (_getParameters == null)
                    {
                        var tt = typeof(ConstructorInfo).BaseType;
                        var method = tt.GetMethod("GetParameters");
                        var para = Expression.Parameter(typeof(ConstructorInfo));
                        _getParameters = Expression.Lambda<Func<ConstructorInfo, ParameterInfo[]>>(Expression.Call(para, method), para).Compile();
                    }
                }
            }
        }
        #endregion

        #region 非引用类型的 IfNullOrDefaultUse & IfDefaultUse
        /// <summary>
        /// 如果是 null 的话返回 value
        /// </summary>
        public static T IfNullUse<T>(this T? obj, T value) where T : struct => (obj == null) ? value : obj.Value;
        /// <summary>
        /// 如果是 null 或 默认值 的话返回 value
        /// </summary>
        public static T IfNullOrInitValueUse<T>(this T? obj, T value) where T : struct => (obj == null || obj.Value.Equals(default(T))) ? value : obj.Value;

        /// <summary>
        /// 如果是 null 的话返回 value
        /// </summary>
        public static T IfDefaultUse<T>(this T obj, T value) where T : struct => (obj.Equals(default(T))) ? value : obj;
        #endregion

        #region 集合/数组/字典的IfNullUse 
        /// <summary>
        /// 如果集合为null则使用空元素集合
        /// </summary>
        public static ICollection<T> IfNullUseEmpty<T>(this ICollection<T> collection)
        {
            if (collection == null || collection.Count == 0) return new List<T>();
            return collection;
        }
        /// <summary>
        /// 如果集合为null则使用空元素集合
        /// </summary>
        public static Collection<T> IfNullUseEmpty<T>(this Collection<T> collection)
        {
            if (collection == null || collection.Count == 0) return new Collection<T>();
            return collection;
        }
        /// <summary>
        /// 如果集合为null则使用空元素集合
        /// </summary>
        public static IList<T> IfNullUseEmpty<T>(this IList<T> collection)
        {
            if (collection == null || collection.Count == 0) return new List<T>();
            return collection;
        }
        /// <summary>
        /// 如果集合为null则使用空元素集合
        /// </summary>
        public static List<T> IfNullUseEmpty<T>(this List<T> collection)
        {
            if (collection == null || collection.Count == 0) return new List<T>();
            return collection;
        }

        /// <summary>
        /// 如果数组为null则使用空元素数组
        /// </summary>
        public static T[] IfNullUseEmpty<T>(this T[] arr)
        {
            if (arr == null) return Array.Empty<T>();
            return arr;
        }

        /// <summary>
        /// 如果字典为null则使用空元素字典
        /// </summary>
        public static IDictionary<TKey, TValue> IfNullUseEmpty<TKey, TValue>(this IDictionary<TKey, TValue> dic)
        {
            if (dic == null) return new Dictionary<TKey, TValue>();
            return dic;
        }
        /// <summary>
        /// 如果字典为null则使用空元素字典
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="dic"></param>
        /// <returns></returns>
        public static Dictionary<TKey, TValue> IfNullUseEmpty<TKey, TValue>(this Dictionary<TKey, TValue> dic)
        {
            if (dic == null) return new Dictionary<TKey, TValue>();
            return dic;
        }
        #endregion

        #region string 的 IfNullOrEmptyUse & IsNullOrWhiteSpaceUse
        /// <summary>
        /// 如果字符串为 null 或者 空字符串,则使用备选值
        /// </summary>
        /// <param name="str"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string IfNullOrEmptyUse(this string str, string value)
        {
            return string.IsNullOrEmpty(str) ? value : str;
        }
        /// <summary>
        /// 如果字符串为 null 或者 空字符串 或者全部是空白符,则使用备选值
        /// </summary>
        /// <param name="str"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string IsNullOrWhiteSpaceUse(this string str, string value)
        {
            return string.IsNullOrWhiteSpace(str) ? value : str;
        }
        #endregion
    }
}
